
#include "xmodule_config.h"

#if MODULE_CHECK_ENABLED( ACCELERATOR )

// <* system header file **>
#include <stdbool.h>
////////////////////////////////////////////////////////////////

// <* platform header files **>
////////////////////////////////////////////////////////////////
#include "rtl876x.h"
#include "rtl876x_rcc.h"
#include "rtl876x_gpio.h"
#include "rtl876x_i2c.h"
#include "rtl876x_nvic.h"
#include "rtl876x_pinmux.h"

#include "app_section.h"
#include "platform_utils.h"
#include "boards.h"
#include "os_timer.h"
#include "os_sched.h"

#include "em_accelerator.h"
// #include ACCEL_INTERNAL_HEADER_FILE

// <* library header files **> 
#include "xDLPS.h"

// Log 
#if MODULE_CHECK_LOG_ENABLED( ACCELERATOR )
#include "log.h"
#define LOG     LOG_INFO
#define LOG0    LOG_INFO0 
#define LOG1    LOG_INFO1
#define LOG2    LOG_INFO2
#define LOG3    LOG_INFO3
#else 
#define LOG(...) 
#define LOG0(...)
#define LOG1(...)
#define LOG2(...)
#define LOG3(...)
#endif 

// Macro for delay 
#define ACCEL_OS_DELAY      os_delay
#define ACCEL_DELAY         platform_delay_ms

#if ACCEL_USE_GPIO_I2C
#include "rtl876x_gpio_i2c_wristband.h"
GPIO_I2C_InitTypeDef accelI2C;
#define ACCEL_BUS_SUCCESS   I2C_GPIO_Success

#define ACCEL_SET_SLAVE_ADDR(x)                         GPIO_I2C_SetSlaveAddr(&accelI2C,x)//accelI2C.I2C_SlaveAddress = x
#define ACCEL_REPEAT_READ(slave, reg, data, datalen )   GPIO_I2C_RepeatRead( &accelI2C, &reg, 1, data, datalen )
#define ACCEL_READ(slave, data, datalen )               GPIO_I2C_MasterRead( &accelI2C, data, datalen )
#define ACCEL_WRITE(slave, reg, data, datalen )         GPIO_I2C_MasterWrite( &accelI2C, reg, datalen + 1 )

#else 

#define ACCEL_BUS_SUCCESS   I2C_Success
#define ACCEL_SET_SLAVE_ADDR(x)                         I2C_SetSlaveAddress( G_SENSOR_I2C_BUS, x )//if share i2c with other peripheral
#define ACCEL_REPEAT_READ(slave, reg, data, datalen)    I2C_RepeatRead(G_SENSOR_I2C_BUS, &reg, 1, data, datalen)
#define ACCEL_READ(slave, data, datalen )               I2C_MasterRead( G_SENSOR_I2C_BUS, data, datalen )
#define ACCEL_WRITE(slave, reg, data, datalen)          I2C_MasterWrite( G_SENSOR_I2C_BUS, reg, datalen + 1 )

#endif 

typedef struct
{
    uint8_t reg;
    uint8_t data[3];
}accel_op_data_t;

static em_accel_data_array_t m_acc_data;

static uint8_t g_sensor_mode = EM_ACCEL_STATE_STOP;

//static uint8_t axis_data_sleep[6];
//static uint8_t axis_data_diff_count, axis_data_same_count; 

static em_acc_event_handle_t m_acc_local_cb = NULL;

void* m_accel_timer = NULL;
bool m_em_acc_is_enabled = false;
//static uint8_t accel_dlps_index = 0;


void accel_timer_start(void);
void accel_timer_restart(uint32_t interval);
static void em_accel_int_enable(void);
static void em_accel_int_disable(void);

#if KX022_CONFIG_ENABLE
#include KX022_DRV_APP_FILE
#endif

#if STK8321_CONFIG_ENABLE
#include STK8321_DRV_APP_FILE
#endif

#include "em_accelerator_list.c"


static const T_IO_MODULE_CBS accelerator_cbs = 
{
    .init = NULL,
    .enter_dlps = em_accel_enter_dlps,
    .exit_dlps = em_accel_exit_dlps,
    .check_allow_dlps = NULL, 
    .system_wakeup_check_allow_dlps = em_accel_system_wakeup_dlps_check,
};
//////////////////////////////////////////////////////////////////////////////////

static void accel_timer_timeout_handler( void* xTimer )
{
    // LOG_INFO1("[%s]: timer timeout \r\n", TRACE_STRING( __FUNCTION__ ) );
    
    if( m_acc_local_cb != NULL )
    {
        em_acc_evt_t evt;
        evt.type = EM_ACC_EVT_TYPE_TIMEOUT;
        m_acc_local_cb ( &evt );
    }
}

void accel_timer_start(void)
{
    if( m_accel_timer != NULL )
    {
        os_timer_start( &m_accel_timer );
    }
}

void accel_timer_restart(uint32_t interval)
{
    if( m_accel_timer != NULL )
    {
        os_timer_restart( &m_accel_timer, interval );
    }
}

void G_SENSOR_SEND_INT_MSG(void)
{
    if( m_em_acc_is_enabled && m_acc_local_cb != NULL )
    {
        em_acc_evt_t evt;
        evt.type = EM_ACC_EVT_TYPE_INT;
        m_acc_local_cb ( &evt );
    }
}


void G_SENSOR_INT_IQR_HANDLER(void)
{
    GPIO_INTConfig( GPIO_GetPin( G_SENSOR_INT_PIN ), DISABLE ); 
    GPIO_MaskINTConfig( GPIO_GetPin( G_SENSOR_INT_PIN ), ENABLE ); 
    GPIO_ClearINTPendingBit( GPIO_GetPin( G_SENSOR_INT_PIN ) );  
  
    G_SENSOR_SEND_INT_MSG();
    
    GPIO_ClearINTPendingBit( GPIO_GetPin( G_SENSOR_INT_PIN ) );
    GPIO_MaskINTConfig( GPIO_GetPin( G_SENSOR_INT_PIN ), DISABLE ); 
    GPIO_INTConfig( GPIO_GetPin( G_SENSOR_INT_PIN ), ENABLE );
}

static void accel_config_gpios(void)
{
    RCC_PeriphClockCmd( APBPeriph_GPIO, APBPeriph_GPIO_CLOCK, ENABLE );
    
    Pad_Config( G_SENSOR_INT_PIN, PAD_PINMUX_MODE, PAD_IS_PWRON, PAD_PULL_UP, PAD_OUT_DISABLE, PAD_OUT_LOW );
    Pinmux_Config( G_SENSOR_INT_PIN, DWGPIO ); 

    Pad_Config( G_SENSOR_SCL_PIN, PAD_PINMUX_MODE, PAD_IS_PWRON, PAD_PULL_UP, PAD_OUT_ENABLE, PAD_OUT_HIGH);
    Pad_Config( G_SENSOR_SDA_PIN, PAD_PINMUX_MODE, PAD_IS_PWRON, PAD_PULL_UP, PAD_OUT_ENABLE, PAD_OUT_HIGH);    

    #if ACCEL_USE_GPIO_I2C
    Pinmux_Config( G_SENSOR_SCL_PIN, DWGPIO );
    Pinmux_Config( G_SENSOR_SDA_PIN, DWGPIO ); 

    GPIO_I2C_StructInit( &accelI2C );
    accelI2C.I2C_SDA_Pin = G_SENSOR_SDA_PIN;
    accelI2C.I2C_SCL_Pin = G_SENSOR_SCL_PIN;
    accelI2C.I2C_SlaveAddress = 0;
    GPIO_I2C_Init( &accelI2C );

    #else 
    RCC_PeriphClockCmd( G_SENSOR_I2C_PERIPH, G_SENSOR_I2C_PERIPH_CLK, ENABLE );
    //    RCC_I2CClkDivConfig(G_SENSOR_I2C_BUS, I2C_CLOCK_DIV_2); 
       

    Pinmux_Config( G_SENSOR_SCL_PIN, G_SENSOR_FUN_SCL );
    Pinmux_Config( G_SENSOR_SDA_PIN, G_SENSOR_FUN_SDA ); 
    
    I2C_InitTypeDef i2cInitStruct;
    I2C_StructInit(&i2cInitStruct);   
    i2cInitStruct.I2C_Clock = 40000000;
    i2cInitStruct.I2C_ClockSpeed = 400000;
    I2C_Init( G_SENSOR_I2C_BUS, &i2cInitStruct );

    I2C_Cmd( G_SENSOR_I2C_BUS, ENABLE );
    #endif 

    GPIO_InitTypeDef gpioInitStruct;
    GPIO_StructInit( &gpioInitStruct ); 
    
    gpioInitStruct.GPIO_Pin                 = GPIO_GetPin( G_SENSOR_INT_PIN ); 
    gpioInitStruct.GPIO_Mode                = GPIO_Mode_IN;
    gpioInitStruct.GPIO_ITCmd               = ENABLE;
    gpioInitStruct.GPIO_ITTrigger           = GPIO_INT_Trigger_EDGE;
    gpioInitStruct.GPIO_ITPolarity          = GPIO_INT_POLARITY_ACTIVE_LOW;
    gpioInitStruct.GPIO_ITDebounce          = GPIO_INT_DEBOUNCE_DISABLE;
    GPIO_Init( &gpioInitStruct ); 
    
    NVIC_InitTypeDef nvicInitStruct;
    nvicInitStruct.NVIC_IRQChannel          = G_SENSOR_INT_IRQn;
    nvicInitStruct.NVIC_IRQChannelPriority  = 3;
    nvicInitStruct.NVIC_IRQChannelCmd       = ENABLE;
    NVIC_Init( &nvicInitStruct ); 
    
    GPIO_INTConfig( GPIO_GetPin( G_SENSOR_INT_PIN), ENABLE ); 
    GPIO_MaskINTConfig( GPIO_GetPin( G_SENSOR_INT_PIN ), DISABLE );
    GPIO_ClearINTPendingBit( GPIO_GetPin( G_SENSOR_INT_PIN ) );
    System_WakeUpPinEnable( G_SENSOR_INT_PIN, PAD_WAKEUP_POL_LOW, PAD_WK_DEBOUNCE_DISABLE ); 

}

static void em_accel_int_enable(void)
{
    m_em_acc_is_enabled = true;
    GPIO_INTConfig( GPIO_GetPin( G_SENSOR_INT_PIN), ENABLE ); 
    GPIO_MaskINTConfig( GPIO_GetPin( G_SENSOR_INT_PIN ), DISABLE );
    GPIO_ClearINTPendingBit( GPIO_GetPin( G_SENSOR_INT_PIN ) );
    System_WakeUpPinEnable( G_SENSOR_INT_PIN, PAD_WAKEUP_POL_LOW, PAD_WK_DEBOUNCE_DISABLE ); 
}
static void em_accel_int_disable(void)
{
    m_em_acc_is_enabled = false;
    GPIO_INTConfig( GPIO_GetPin( G_SENSOR_INT_PIN), DISABLE ); 
    GPIO_MaskINTConfig( GPIO_GetPin( G_SENSOR_INT_PIN ), ENABLE );
    GPIO_ClearINTPendingBit( GPIO_GetPin( G_SENSOR_INT_PIN ) );
    System_WakeUpPinDisable( G_SENSOR_INT_PIN ); 
}
void em_accel_enter_dlps(void)
{
   Pad_Config( G_SENSOR_SCL_PIN, PAD_SW_MODE, PAD_IS_PWRON, PAD_PULL_UP, PAD_OUT_DISABLE, PAD_OUT_HIGH );
   Pad_Config( G_SENSOR_SDA_PIN, PAD_SW_MODE, PAD_IS_PWRON, PAD_PULL_UP, PAD_OUT_DISABLE, PAD_OUT_HIGH ); 

    Pad_Config( G_SENSOR_INT_PIN, PAD_SW_MODE, PAD_IS_PWRON, PAD_PULL_UP, PAD_OUT_DISABLE, PAD_OUT_LOW ); 
}

void em_accel_exit_dlps(void)
{
   Pad_Config( G_SENSOR_SCL_PIN, PAD_PINMUX_MODE, PAD_IS_PWRON, PAD_PULL_UP, PAD_OUT_ENABLE, PAD_OUT_HIGH );
   Pad_Config( G_SENSOR_SDA_PIN, PAD_PINMUX_MODE, PAD_IS_PWRON, PAD_PULL_UP, PAD_OUT_ENABLE, PAD_OUT_HIGH ); 

    Pad_Config( G_SENSOR_INT_PIN, PAD_PINMUX_MODE, PAD_IS_PWRON, PAD_PULL_UP, PAD_OUT_DISABLE, PAD_OUT_LOW ); 
}
bool em_accel_system_wakeup_dlps_check(void)
{
    if( System_WakeUpInterruptValue( G_SENSOR_INT_PIN) == SET ) 
    {
        Pad_ClearWakeupINTPendingBit( G_SENSOR_INT_PIN ); 
        return true; 
    }
    return false; 
}

void em_accel_init(void)
{
    accel_config_gpios();    
    
    if( m_accel_timer == NULL )
    {
        os_timer_create( &m_accel_timer, "g_sensor_timer", 0, 200, false, accel_timer_timeout_handler );
    }

}

void em_accel_init_dlps(void)
{
    /*accel_dlps_index = */
    uint32_t index = xDLPS_register( & accelerator_cbs );
    LOG1("[ACCEL]: DLPS index = %d\r\n", index );
}

void em_accel_register_cb(em_acc_event_handle_t cb)
{
    m_acc_local_cb = cb; 
}

#endif 
